package com.tianyu.inspection.service;

import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itextpdf.xmp.impl.Base64;
import com.tianyu.inspection.common.Constants;
import com.tianyu.inspection.common.enums.RoState;
import com.tianyu.inspection.common.enums.Role;
import com.tianyu.inspection.common.model.PageModel;
import com.tianyu.inspection.service.api.IUserService;
import com.tianyu.inspection.service.websocket.server.WebSocketServer;
import com.tianyu.inspection.common.component.AppConstants;
import com.tianyu.inspection.entity.Project;
import com.tianyu.inspection.entity.User;
import com.tianyu.inspection.entity.model.OperateMo;
import com.tianyu.inspection.entity.model.QueryMo;
import com.tianyu.inspection.entity.model.WebSocketChannelMo;
import com.tianyu.inspection.entity.vo.Ro;
import com.tianyu.inspection.mapper.ProjectMapper;
import com.tianyu.inspection.mapper.RoleMapper;
import com.tianyu.inspection.mapper.UserMapper;
import io.ocs.common.OcsConstants;
import io.ocs.model.OcsSimpleModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**********************************
 * @Author YSW
 * @Description 用户登录注册服务
 * @Date 2021/1/7 - 11:20
 **********************************/

@Slf4j
@Service
public class UserServiceImpl implements IUserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private ProjectMapper projectMapper;

    @Resource
    private AppConstants appConstants;

    @Resource
    private OcsConstants ocsConstants;

    @Resource
    private ValueOperations<String, Object> valueOperations;

    @Resource
    private OcsSimpleModel ocsSimpleModel;

    /**
     * 用户登录
     *
     * @param requestUser 请求用户信息（用户名、密码）
     * @return 用户信息（token）
     */
    @Override
    public Ro<User> login(User requestUser) {
        Ro<User> userRo = new Ro<>();
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.or((wrapper)->{
            wrapper.eq("user_name", requestUser.getUserName()).eq("password", Base64.encode(requestUser.getPassword()));
        }).or((wrapper)->{
            wrapper.eq("phone", requestUser.getUserName()).eq("password", Base64.encode(requestUser.getPassword()));
        });
        try {
            User responseUser = userMapper.selectOne(queryWrapper);
            if (Objects.nonNull(responseUser)) {
                if (responseUser.getState() == 0) {
                    String token = UUID.randomUUID().toString().replace("-", "").toUpperCase();
                    //更新数据库
                    responseUser.setLastIp(requestUser.getLastIp());
                    responseUser.setLastTime(new Date());
                    responseUser.setToken(token);
                    userMapper.updateById(new User()
                            .setId(responseUser.getId())
                            .setLastIp(responseUser.getLastIp())
                            .setLastTime(responseUser.getLastTime())
                            .setToken(responseUser.getToken())
                    );
                    responseUser.setPassword(null);
                    responseUser.setState(null);
                    if (Objects.nonNull(responseUser.getAvatarUrl())) {
                        responseUser.setAvatarUrl(ocsSimpleModel.getObjectUrl(responseUser.getAvatarUrl()));
                    }
                    Integer projectId = responseUser.getProjectId();
                    Integer roleId = responseUser.getRoleId();
                    if (Objects.nonNull(roleId)) {
                        responseUser.setRole(roleMapper.selectById(roleId));
                    }
                    Project project = projectMapper.selectById(projectId);
                    if (Objects.nonNull(project)) {
                        String clientModule = project.getClientModule();
                        String tiltPhotographUrl = project.getTiltPhotographUrl();
                        String iUse = project.getInfrastructureTypeUse();
                        if (Objects.nonNull(iUse)) {
                            responseUser.setInfrastructureTypeUse(iUse);
                            JSONArray objects = JSONArray.parseArray(iUse);
                            for (Object object : objects) {
                                if (object.equals(1)) {
                                    responseUser.setPileCardTypeUse(project.getPileCardTypeUse());
                                } else if (object.equals(2)) {
                                    responseUser.setGeneralFacilitiesTypeUse(project.getGeneralFacilitiesTypeUse());
                                } else if (object.equals(3)) {
                                    responseUser.setHighConsequenceAreaTypeUse(project.getHighConsequenceAreaTypeUse());
                                } else if (object.equals(4)) {
                                    responseUser.setConstructionTypeUse(project.getConstructionTypeUse());
                                } else if (object.equals(5)) {
                                    responseUser.setCameraTypeUse(project.getCameraTypeUse());
                                }
                            }
                        }
                        responseUser.setSysTypeUse(project.getSysTypeUse());
                        responseUser.setClientModule(clientModule);
                        responseUser.setTiltPhotographUrl(tiltPhotographUrl);
                        if (roleId > 1) {
                            responseUser.setClientLogo(ocsSimpleModel.getObjectUrl(project.getClientLogo()));
                            responseUser.setClientName(project.getClientName());
                        }
                    }
                    responseUser.setResourceHost(ocsConstants.getResourcePrefix());
                    userRo.setResultEnum(RoState.SUCCESS);
                    userRo.setContent(responseUser);
                    try {
                        valueOperations.set(appConstants.redisUserKey + responseUser.getId(), responseUser, 7, TimeUnit.DAYS);
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("用户[{}]登录信息 redis 缓存失败", responseUser.getId());
                        return new Ro<>(RoState.SYS_SERVER_ERROR);
                    }
                } else {
                    userRo.setResultEnum(RoState.FAIL);
                    userRo.setMessage("该用户账号已被冻结，请联系客服");
                }
            } else {
                userRo.setResultEnum(RoState.FAIL);
                userRo.setMessage("用户名或密码不正确");
            }
            return userRo;
        } catch (Exception e) {
            userRo.setResultEnum(RoState.SYS_SERVER_ERROR);
            log.error("服务器错误,登录异常");
            e.printStackTrace();
            return userRo;
        }
    }

    @Override
    public Ro<Void> logout(Integer uid, String token) {
        Ro<Void> resultInfo = new Ro<>(RoState.SUCCESS);
        Object o = valueOperations.get(appConstants.redisUserKey + uid);
        ObjectMapper objectMapper = new ObjectMapper();
        User user = objectMapper.convertValue(o, User.class);
        String userToken = user.getToken();
        if (!Objects.equals(userToken, token)) {
            resultInfo.setResultEnum(RoState.USER_LOGOUT_ERROR);
            resultInfo.setMessage("Token错误, 退出登录失败！");
            return resultInfo;
        } else {
            try {
                valueOperations.getOperations().delete(appConstants.redisUserKey + uid);
                WebSocketChannelMo webSocketChannelMo = WebSocketServer.WEB_SOCKET_CHANNEL_MAP.get(uid);
                if (Objects.nonNull(webSocketChannelMo)) {
                    webSocketChannelMo.getChannel().close();
                    WebSocketServer.WEB_SOCKET_CHANNEL_MAP.remove(uid);
                }
            } catch (Exception e) {
                log.error("用户{}退出登录异常", uid);
                return new Ro<>(RoState.USER_LOGOUT_ERROR);
            }
        }
        return resultInfo;
    }

    /**
     * 分页查询
     *
     * @param queryMo 参数模型
     * @return ModelMap
     */
    @Override
    public IPage<User> searchListPage(QueryMo queryMo) {
        final User searchUser = Constants.USER_THREAD_LOCAL.get();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.allEq(queryMo.getEqMap());
        String ascParams = queryMo.getAscParams();
        String descParams = queryMo.getDescParams();
        if (Objects.nonNull(ascParams) && !Objects.equals(ascParams, "")) {
            wrapper.orderByAsc(ascParams);
        }
        if (Objects.nonNull(descParams) && !Objects.equals(descParams, "")) {
            wrapper.orderByDesc(descParams);
        }
        final QueryWrapper<User> modelWrapper = PageModel.getModelWrapper(queryMo);
        if (queryMo.get("roleId").equals(1)){
            modelWrapper.gt("role_id",1);
        }
        if (queryMo.get("roleId").equals(2)){
            modelWrapper.gt("role_id",2);
        }
        IPage<User> page = PageModel.getModelPage(modelWrapper,queryMo,userMapper);
        page.getRecords().forEach((user -> {
            if (Objects.nonNull(user.getAvatarUrl())) {
                user.setAvatarUrl(ocsSimpleModel.getObjectUrl(user.getAvatarUrl()));
            }
            if (Objects.nonNull(user.getPassword()) && searchUser.getRoleId() == Role.ROLE_SUPER_ADMIN.getValue()) {
                user.setPassword(Base64.decode((user.getPassword())));
            }else {
                user.setPassword(null);
                user.setToken(null);
            }
            user.setIsOnline(WebSocketServer.WEB_SOCKET_CHANNEL_MAP.containsKey(user.getId()));
        }));
        return page;
    }

    /**
     * 通过ID查询一条数据
     *
     * @param queryMo 参数集[实体ID 与 项目ID, 数据状态等]
     * @return
     */
    @Override
    public User selectOne(QueryMo queryMo) {
        if (Objects.isNull(queryMo.getEqMap().get("id")) &&
                Objects.isNull(queryMo.getEqMap().get("user_name")) &&
                Objects.isNull(queryMo.getEqMap().get("phone"))) {
            return null;
        }
        Integer roleId = (Integer) queryMo.get("roleId");
        QueryWrapper<User> wrapper = new QueryWrapper<User>().allEq(queryMo.getEqMap());
        if (Objects.nonNull(roleId)) {
            wrapper.gt("role_id", roleId);
        }
        User user = userMapper.selectOne(wrapper);
        if (Objects.nonNull(user) && Objects.nonNull(user.getAvatarUrl())) {
            user.setAvatarUrl(ocsSimpleModel.getObjectUrl(user.getAvatarUrl()));
        }
        return user;
    }

    /**
     * 查询用户(判断用户是否存在)
     *
     * @param username
     * @return
     */
    @Override
    public User selectUserByUsername(String username) {
        if (Objects.isNull(username)) {
            return null;
        }
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .eq("user_name", username);
        User user = userMapper.selectOne(wrapper);
        if (Objects.nonNull(user) && Objects.nonNull(user.getAvatarUrl())) {
            user.setAvatarUrl(ocsSimpleModel.getObjectUrl(user.getAvatarUrl()));
        }
        return user;
    }

    /**
     * 查询用户(判断用户是否存在)
     *
     * @param phone
     * @return
     */
    @Override
    public User selectUserByUserPhone(String phone) {
        if (Objects.isNull(phone)) {
            return null;
        }
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .eq("phone", phone);
        User user = userMapper.selectOne(wrapper);
        if (Objects.nonNull(user) && Objects.nonNull(user.getAvatarUrl())) {
            user.setAvatarUrl(ocsSimpleModel.getObjectUrl(user.getAvatarUrl()));
        }
        return user;
    }

    /**
     * 通过ID查询一条数据
     *
     * @param queryMo 参数集[实体ID 与 项目ID, 数据状态等]
     * @return
     */
    @Override
    public Integer selectCount(QueryMo queryMo) {
        return Math.toIntExact(userMapper.selectCount(new QueryWrapper<User>().allEq(queryMo.getEqMap())));
    }

    /**
     * 插入一条数据
     *
     * @param operateMo 实体对象
     * @return 是否操作成功
     */
    @Override
    public boolean insert(OperateMo operateMo) {
        ObjectMapper objectMapper = new ObjectMapper();
        User user = objectMapper.convertValue(operateMo.getEntity(), User.class);
        return 1 == userMapper.insert(user);
    }

    /**
     * 通过ID删除一条数据
     *
     * @param queryMo 参数集[实体ID 与 项目ID, 数据状态等]
     * @return 是否操作成功
     */
    @Override
    public boolean delete(QueryMo queryMo) {
        if (Objects.nonNull(queryMo.getEqMap().get("id"))) {
            return 1 == userMapper.delete(new QueryWrapper<User>().allEq(queryMo.getEqMap()));
        }
        return false;
    }

    /**
     * 插入一条数据
     *
     * @param operateMo 更新参数集
     * @return ModelMap
     */
    @Override
    public boolean update(OperateMo operateMo) {
        ObjectMapper objectMapper = new ObjectMapper();
        User user = objectMapper.convertValue(operateMo.getEntity(), User.class);
        if (Objects.nonNull(operateMo.get("password"))) {
            user.setPassword((String) operateMo.get("password"));
        }
        return 1 == userMapper.update(user, new QueryWrapper<User>().allEq(operateMo.getEqMap()));
    }

    /**
     * 通过ID逻辑删除一条数据
     *
     * @param queryMo 参数集[实体ID 与 项目ID, 数据状态]
     * @return 是否操作成功
     */
    @Override
    public boolean logicallyDelete(QueryMo queryMo) {
        return 1 == userMapper.update(
                new User().setState(1),
                new QueryWrapper<User>().allEq(queryMo.getEqMap())
        );
    }

    /**
     * 用户登录
     *
     * @param userId 用户ID
     * @return 用户信息
     */
    @Override
    public User cacheUserById(Integer userId) {
        Object responseUser = valueOperations.get(appConstants.redisUserKey + userId);
        if (Objects.nonNull(responseUser)) {
            return new ObjectMapper().convertValue(responseUser, User.class);
        }
        return null;
    }
}
